---
title: "HHH015007: Illegal argument on static metamodel field inject"
date: 2019-6-11
categories:
- java
- spring-jpa
tags:
---

<div id="content">
<blockquote>
<p>
<a href="https://forum.hibernate.org/viewtopic.php?t=1045003">https://forum.hibernate.org/viewtopic.php?t=1045003</a>
</p>
</blockquote>
<div class="org-src-container">
<pre class="src src-java"><span style="font-weight: bold; font-style: italic;">// </span><span style="font-weight: bold; font-style: italic;">entity class</span>

<span style="font-weight: bold; text-decoration: underline;">@Convert</span>(converter = ClassSimpleNameConverter.<span style="font-weight: bold;">class</span>)
<span style="font-weight: bold;">private</span> <span style="font-weight: bold; text-decoration: underline;">Set</span>&lt;<span style="font-weight: bold; text-decoration: underline;">Class</span>&lt;?&gt;&gt; <span style="font-weight: bold; font-style: italic;">types</span>;

<span style="font-weight: bold; font-style: italic;">// </span><span style="font-weight: bold; font-style: italic;">class ClassSimpleNameConverter</span>
<span style="font-weight: bold; font-style: italic;">/* </span><span style="font-weight: bold; font-style: italic;">@see javax.persistence.AttributeConverter#convertToDatabaseColumn(java.lang.Object) */</span>
<span style="font-weight: bold; text-decoration: underline;">@Override</span>
<span style="font-weight: bold;">public</span> <span style="font-weight: bold; text-decoration: underline;">String</span> <span style="font-weight: bold;">convertToDatabaseColumn</span>(<span style="font-weight: bold;">final</span> <span style="font-weight: bold; text-decoration: underline;">Set</span>&lt;<span style="font-weight: bold; text-decoration: underline;">Class</span>&lt;? <span style="font-weight: bold;">extends</span> <span style="font-weight: bold; text-decoration: underline;">T</span>&gt;&gt; <span style="font-weight: bold; font-style: italic;">actual</span>)
{
   <span style="font-weight: bold;">if</span> (actual == <span style="font-weight: bold; text-decoration: underline;">null</span>) <span style="font-weight: bold;">return</span> <span style="font-weight: bold; text-decoration: underline;">null</span>;
   <span style="font-weight: bold;">return</span> actual.stream()
      .map(Class::getSimpleName)
      .filter(t -&gt; types.containsKey(t))
      .collect(Collectors.joining(<span style="font-style: italic;">","</span>));
}

<span style="font-weight: bold; font-style: italic;">/* </span><span style="font-weight: bold; font-style: italic;">@see javax.persistence.AttributeConverter#convertToEntityAttribute(java.lang.Object) */</span>
<span style="font-weight: bold; text-decoration: underline;">@Override</span>
<span style="font-weight: bold;">public</span> <span style="font-weight: bold; text-decoration: underline;">Set</span>&lt;<span style="font-weight: bold; text-decoration: underline;">Class</span>&lt;? <span style="font-weight: bold;">extends</span> <span style="font-weight: bold; text-decoration: underline;">T</span>&gt;&gt; <span style="font-weight: bold;">convertToEntityAttribute</span>(<span style="font-weight: bold;">final</span> <span style="font-weight: bold; text-decoration: underline;">String</span> <span style="font-weight: bold; font-style: italic;">dbData</span>)
{
   <span style="font-weight: bold;">if</span> (dbData == <span style="font-weight: bold; text-decoration: underline;">null</span>) <span style="font-weight: bold;">return</span> <span style="font-weight: bold; text-decoration: underline;">null</span>;
   <span style="font-weight: bold;">return</span> Arrays.stream(dbData.split(<span style="font-style: italic;">","</span>))
      .map(t -&gt; types.get(t))
      .collect(Collectors.toSet());
}

</pre>
</div>
<p>
This works nicely except when creating the JPA meta model for the entity using Hibernate's meta model generator, version 5.2.12 (pretty recent :-). Due to the fact that the unconverted field's type is `Set`, the corresponding constant in the metamodel is typed to `SetAttribute&lt;MyEntity, Class&gt; types`. This, in turn, leads to the following exception when the container deploys the application:
使用 Hibernate's meta model generator ，生成的 entity metadata class, 容器部署时报错：
</p>
<blockquote>
<p>
ERROR [org.hibernate.metamodel.internal.MetadataContext] (ServerService Thread Pool – 66) HHH015007: Illegal argument on static metamodel field injection : 
mypackage.MyEntity_#types; expected type :  
org.hibernate.metamodel.internal.SingularAttributeImpl; 
encountered type : javax.persistence.metamodel.SetAttribute
</p>
</blockquote>
<p>
To me, this appears to be a kind of corner case, if not a gap in the design of the JPA specification. What would be the correct behavior here? Should the meta model generator consider the target type of an AttributeConverter (which is String in this case). I tried to annotate the field as @Basic but that didn't have an effect.
</p>
<p>
Hibernate Team:
We have added an example for a <a href="http://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#collections-as-basic">comma-delimited</a> String Type in our User Guide.
</p>
<p>
Unlike that StackOverflow question, we are using a Hibernate custom Type which is way superior to JPA AttributeConverter.
</p>
<p>
Poster:
Nice. Still, why do we invest so much time and efforts in a thing called JPA in the first place, if every second answer I get when using something out of the JPA standard is like "hey, forget about JPA and use our (proprietary) stuff". To a large degree, we are using JPA because we want to remain portable. What precisely makes a Hibernate custom type way superior to a JPA AttributeConverter? Second, can we stick to the question, please. What would be the correct behavior for the JPA meta model generator if it sees a field that seems to be a collection field but which is actually not because of an additional AttributeConverter? What about the exception thrown at runtime?
</p>
<p>
Hibernate Team:
It's the same with SQL Standard, isn't it?
</p>
<p>
Poster:
Sure, that's the case for pretty much every standard for which there are different implementations. But that does not justify suggesting its a bad/naive/unrealisitic idea if someone wants to stick with the standard; in particular, if there is no need to use non-standard features. Which brings us back to the question what precisely makes a Hibernate custom type way superior to a JPA AttributeConverter?
</p>
<p>
Hibernate Team:
The best way to answer your question is to ask you to <a href="https://vladmihalcea.com/how-to-store-schema-less-eav-entity-attribute-value-data-using-json-and-hibernate/">try to map a Jackson JsonNode with Attributeconverter</a> or <a href="https://vladmihalcea.com/how-to-map-java-and-sql-arrays-with-jpa-and-hibernate/">a PostgreSQL ARRAY</a> if you want.
</p>
<p>
Since the Attributeconverter does not give you access to the underlying JDBC PreparedStatement or ResultSet, you'll see that it's not very easy to achieve that goal.
</p>
<p>
Hibernate 团队称使用 @Type (Hibernate特征）能解决问题，但是这么做就失去了JPA的移植性。
</p>
</div>
<div class="status" id="postamble">
<p class="date">Date: 2019-6-11</p>
<p class="author">Author: gdme1320</p>
<p class="validation"><a href="http://validator.w3.org/check?uri=referer">Validate</a></p>
</div>
